/*******************************************************************************
 * Copyright (c) 2000, 2008 IBM Corporation and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *     IBM Corporation - initial API and implementation
 *     Eclipse Foundation - Modified from org.eclipse.jdt.internal.ui.packageview.PackageExplorerPart
 *******************************************************************************/
package org.schemeway.plugins.schemescript.views;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspace;
import org.eclipse.core.runtime.IAdaptable;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.internal.ui.actions.RunAsAction;
import org.eclipse.debug.ui.DebugUITools;
import org.eclipse.debug.ui.IDebugUIConstants;
import org.eclipse.debug.ui.actions.RunAction;
import org.eclipse.jdt.core.ICompilationUnit;
import org.eclipse.jdt.core.IJavaElement;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.internal.core.CompilationUnit;
import org.eclipse.jdt.internal.core.PackageFragment;
import org.eclipse.jdt.internal.ui.JavaPlugin;
import org.eclipse.jdt.internal.ui.packageview.PackageExplorerContentProvider;
import org.eclipse.jdt.internal.ui.packageview.PackageExplorerLabelProvider;
import org.eclipse.jdt.internal.ui.refactoring.reorg.DeleteAction;
import org.eclipse.jdt.ui.JavaElementComparator;
import org.eclipse.jdt.ui.actions.NavigateActionGroup;
import org.eclipse.jdt.ui.actions.OpenNewClassWizardAction;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.action.IAction;
import org.eclipse.jface.action.IMenuListener;
import org.eclipse.jface.action.IMenuManager;
import org.eclipse.jface.action.IToolBarManager;
import org.eclipse.jface.action.MenuManager;
import org.eclipse.jface.action.Separator;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.*;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.jface.viewers.DoubleClickEvent;
import org.eclipse.jface.viewers.IDoubleClickListener;
import org.eclipse.jface.viewers.IOpenListener;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.OpenEvent;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.TreePath;
import org.eclipse.jface.viewers.TreeSelection;
import org.eclipse.swt.SWT;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Menu;
import org.eclipse.ui.IActionBars;
import org.eclipse.ui.IActionDelegate2;
import org.eclipse.ui.ISharedImages;
import org.eclipse.ui.IWorkbenchActionConstants;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.part.ISetSelectionTarget;
import org.eclipse.ui.part.ViewPart;
import org.schemeway.plugins.schemescript.*;
import org.schemeway.plugins.schemescript.wizards.*;


public class SchemePackageExplorer extends ViewPart implements IPropertyChangeListener,ISetSelectionTarget {
	private SchemePackageExplorerProblemTreeViewer viewer;
	private Action newFileAction;
	//private Action newPackageAction;
	private Action newProjectAction;
	private Action doubleClickAction;
	private Action deleteAction;
	//private Action runAsAction;
	private Action runLastAction;
	
	private SchemePackageExplorerContentProvider contentProvider;
	private PackageExplorerLabelProvider labelProvider;
	private NavigateActionGroup navigateActionGroup;
	
	public static String ID ="org.schemeway.plugins.schemescript.packageExplorer";
	


	public SchemePackageExplorer() {
	}
	
	

	public void createPartControl(Composite parent) {
		viewer = new SchemePackageExplorerProblemTreeViewer(parent, SWT.MULTI | SWT.H_SCROLL | SWT.V_SCROLL);
		contentProvider = new SchemePackageExplorerContentProvider(false);
		viewer.setContentProvider(contentProvider);
		labelProvider = new PackageExplorerLabelProvider(contentProvider);
		viewer.setLabelProvider(labelProvider);
		//viewer.setComparator(new JavaElementComparator());
		viewer.setUseHashlookup(true);
		getSite().setSelectionProvider(viewer);
		
		navigateActionGroup= new NavigateActionGroup(this); 
		JavaPlugin.getDefault().getPreferenceStore().addPropertyChangeListener(this);
		
		makeActions();
		hookContextMenu();
		//hookDoubleClickAction();
		contributeToActionBars();
		viewer.setInput(findInputElement());
		
		//add to open editor on selected Java classes
		viewer.addOpenListener(new IOpenListener() {
			public void open(OpenEvent event) {
				IAction openAction= navigateActionGroup.getOpenAction();
				if (openAction != null && openAction.isEnabled()) {
					openAction.run();
					return;
				}
				
			}
		});
		viewer.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent event) {
				boolean setEnabled = false;
				// if the selection is empty return
				if(event.getSelection().isEmpty()) {
					deleteAction.setEnabled(false);
					return;
				}
				
				deleteAction.setEnabled(true);
				
				if(event.getSelection() instanceof IStructuredSelection) {
					IStructuredSelection selection =
						 (IStructuredSelection)event.getSelection();
					if (selection instanceof TreeSelection){
						TreeSelection treeSelection = (TreeSelection)selection;
						Object object = treeSelection.getFirstElement();
						if (object instanceof CompilationUnit){
							setEnabled=true;
						}
					}
					else if (selection instanceof StructuredSelection){
							Object object = selection.getFirstElement();
							if (object instanceof CompilationUnit){
								setEnabled=true;
							}
						}
					}
				//runAsAction.setEnabled(setEnabled);
			}
		});
		
		setPartName("Scheme Package Explorer");

	}

	private void hookContextMenu() {
		MenuManager menuMgr = new MenuManager("#PopupMenu");
		menuMgr.setRemoveAllWhenShown(true);
		menuMgr.addMenuListener(new IMenuListener() {
			public void menuAboutToShow(IMenuManager manager) {
				SchemePackageExplorer.this.fillContextMenu(manager);
			}
		});
		Menu menu = menuMgr.createContextMenu(viewer.getControl());
		viewer.getControl().setMenu(menu);
		/* Don't register menu with viewer otherwise other plugins will
		 * contributed to the menu
		 */
		//getSite().registerContextMenu(menuMgr, viewer);
	}

	private void contributeToActionBars() {
		IActionBars bars = getViewSite().getActionBars();
		fillLocalPullDown(bars.getMenuManager());
		fillLocalToolBar(bars.getToolBarManager());
	}

	private void fillLocalPullDown(IMenuManager manager) {
		manager.add(newProjectAction);
		manager.add(newFileAction);
		manager.add(new Separator());
		manager.add(deleteAction);
		/*manager.add(new Separator());
		manager.add(runAsAction);*/
	}

	private void fillContextMenu(IMenuManager manager) {
		manager.add(newProjectAction);
		manager.add(newFileAction);
		manager.add(new Separator());
		manager.add(deleteAction);
		manager.add(new Separator());
		//manager.add(runAsAction);
		// Other plug-ins can contribute there actions here
		//manager.add(new Separator(IWorkbenchActionConstants.MB_ADDITIONS));
	}
	
	private void fillLocalToolBar(IToolBarManager manager) {
		manager.add(newProjectAction);
		manager.add(newFileAction);
		manager.add(new Separator());
		manager.add(deleteAction);
		//manager.add(new Separator());
		//manager.add(runLastAction);
	}

	private void makeActions() {
		newFileAction = new OpenNewSchemeFileWizardAction();
		newProjectAction = new NewEmptyProjectWizardAction();
		deleteAction = new DeleteAction(getSite());
		deleteAction.setEnabled(false);

		//runAsAction = new LiteLaunchShortcutsAction(IDebugUIConstants.ID_RUN_LAUNCH_GROUP);
		//runAsAction.setEnabled(false);
		/* left as a reminder
		runLastAction =  new Action() {
			public void run() {
				RunAction action = new RunAction();
				action.run(null);
			}
		};
		runLastAction.setText("Run Last");
		runLastAction.setEnabled(false);
		*/
	}

	private void hookDoubleClickAction() {
		viewer.addDoubleClickListener(new IDoubleClickListener() {
			public void doubleClick(DoubleClickEvent event) {
				doubleClickAction.run();
			}
		});
	}
	private void showMessage(String message) {
		MessageDialog.openInformation(
			viewer.getControl().getShell(),
			"Sample View",
			message);
	}


	public void setFocus() {
		viewer.getControl().setFocus();
	}
	
	public void propertyChange(PropertyChangeEvent event) {
		if (viewer == null)
			return;
		getSite().getShell().getDisplay().asyncExec (new Runnable () {
		      public void run () {
		    	  viewer.refresh();
		      }
		   });
	}
	
	private Object findInputElement() {
		Object input= getSite().getPage().getInput();
		if (input instanceof IWorkspace) { 
			return JavaCore.create(((IWorkspace)input).getRoot());
		} else if (input instanceof IContainer) {
			IJavaElement element= JavaCore.create((IContainer)input);
			if (element != null && element.exists())
				return element;
			return input;
		}
			//1GERPRT: ITPJUI:ALL - Packages View is empty when shown in Type Hierarchy Perspective
			// we can't handle the input
			// fall back to show the workspace
		return JavaCore.create(JavaPlugin.getWorkspace().getRoot());
	}
	
	  public Object getAdapter(Class adapter) {
		  if (adapter == ISetSelectionTarget.class)
			  return this;
		  return super.getAdapter(adapter);
	  }



	public void selectReveal(final ISelection selection) {
			Control ctrl= viewer.getControl();
			if (ctrl == null || ctrl.isDisposed())
				return;

			contentProvider.runPendingUpdates();
			viewer.setSelection(convertSelection(selection), true);	
	}
	
	public ISelection convertSelection(ISelection s) {
		if (!(s instanceof IStructuredSelection))
			return s;
			
		Object[] elements= ((IStructuredSelection)s).toArray();
		
		boolean changed= false;
		for (int i= 0; i < elements.length; i++) {
			Object convertedElement= convertElement(elements[i]);
			changed= changed || convertedElement != elements[i];
			elements[i]= convertedElement;
		}
		if (changed)
			return new StructuredSelection(elements);
		else
			return s;
	}
	
	private Object convertElement(Object original) {
		if (original instanceof IJavaElement) {
			if (original instanceof ICompilationUnit) {
				ICompilationUnit cu= (ICompilationUnit) original;
				IJavaProject javaProject= cu.getJavaProject();
				if (javaProject != null && javaProject.exists() && ! javaProject.isOnClasspath(cu)) {
					// could be a working copy of a .java file that is not on classpath 
					IResource resource= cu.getResource();
					if (resource != null)
						return resource;
				}
				
			}
			return original;
		
		} else if (original instanceof IResource) {
			IJavaElement je= JavaCore.create((IResource)original);
			if (je != null && je.exists()) {
				IJavaProject javaProject= je.getJavaProject();
				if (javaProject != null && javaProject.exists()) {
					return je;
				}
			}
		} else if (original instanceof IAdaptable) {
			IAdaptable adaptable= (IAdaptable)original;
			IJavaElement je= (IJavaElement) adaptable.getAdapter(IJavaElement.class);
			if (je != null && je.exists())
				return je;
			
			IResource r= (IResource) adaptable.getAdapter(IResource.class);
			if (r != null) {
				je= JavaCore.create(r);
				if (je != null && je.exists()) 
					return je;
				else
					return r;
			}
		}
		return original;
	}
	  
}
